//
// Created by hsj on 2024-1-8.
// Windows没有fork
// 杀死僵尸进程
// ****************************************************僵尸进程定义***************************************************
// “应该向创建子进程的父进程传递子进程的exit参数值或return语句的返回值。”
// 如何向父进程传递这些值呢?操作系统不会主动把这些值传递给父进程。
// 只有父进程主动发起请求(函数调用)时，操作系统才会传递该值。
// 换言之，如果父进程未主动要求获得子进程的结束状态值，操作系统将-直保存， 并让子进程长时间处于僵尸进程状态。
// 也就是说，父母要负责收回自己生的孩子(也许这种描述有些不妥)。
// ****************************************************僵尸进程定义[结束]***************************************************

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#ifdef WIN32
//windows minGW64
//inet_ntop函数：_WIN32_WINNT
#ifdef _WIN32_WINNT
#undef _WIN32_WINNT
#endif
#define _WIN32_WINNT 0x0600
#include <winsock2.h>
#include <ws2tcpip.h>
//#pragma comment(lib,"ws2_32.lib")
#else
//linux  gcc
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/wait.h>
#include <signal.h>
#endif
void error_handling(char *message);

void read_childproc(int sig){
    int status;
    //非阻塞式退出进程
    //waitpid第一个参数：等待终止的目标子进程的ID，若传递-1，则与wait函数相同，可以等待任意子进程终止。
    pid_t id=waitpid(-1, &status, WNOHANG) ;
    if(WIFEXITED( status)){//检测退出了吗
        printf("Removed sub proc id: %d \n", id);
        printf("Child send: %d \n", WEXITSTATUS(status));//获取退出的子进程的退出码/返回值
    }
}

int main(int argc, char *argv[]){
    pid_t pid;
    /**
    * struct sigaction
      {
           void (*sa_handler)(int);
           sigset_t sa_mask;
           int sa_flags;
      }
       此结构体的sa_handler成 员保存信号处理函数的指针值(地址值)。
       sa_mask和sa_flags的所有位均初始化为0即可。这2个成员用于指定信号相关的选项和特性，而我们的目的主要是防止产生僵尸进程，故省略。

    */
    struct sigaction act;
    act.sa_handler=read_childproc;
    sigemptyset(&act.sa_mask);
    act.sa_flags=0;

    //注册子进程结束事件
    sigaction(SIGCHLD, &act, 0);

    pid=fork();
    if(pid==0) /*子进程执行区域*/
    {
        puts("Hi! I'm child process");
        sleep(10);
        return 18;
    }
    else/*父进程执行区域*/
    {
        printf("Child proc id: %d \n", pid);
        pid=fork();
        if(pid==0) /*另一子进程执行区域*/
        {
            puts("Hi! I'm other child process");
            sleep(10);
            exit(20);
        }
        else
        {
            int i;
            printf("other Child proc id: %d \n", pid);

            //主进程等待
            for(i=0; i<5; i++)
            {
                puts("wait...");
                /**
                *  1)已经过了seconds所指定的墙上时钟时间
                *  2)发生信号时将唤醒由于调用sleep函数而进入阻塞状态的进程
                */
                sleep(5);
            }
        }
    }

    return EXIT_SUCCESS;
}

void error_handling(char *message){
    fputs (message, stderr);
    fputc('\n', stderr);
    exit(1);
}
